using System;
using System.Collections.Generic;
using System.Dynamic;
using RimWorld;
using Verse;
using Verse.AI;

namespace RimZombieGirl
{
    // 参考 JobDriver_SuppressSlave
    // TODO 需要修改
    public class JobDriver_SuppressZombie : JobDriver
    {
        // 抑制僵尸行为的持续时间，设定为180游戏刻（约3秒，每秒60刻）
        private int SuppressDuration = 180;

        // 获取当前作业目标A所对应的僵尸Pawn对象
        // job.targetA 通常是作业的目标实体，此处强制转换为Pawn类型
        protected Pawn Zombie => (Pawn)job.targetA.Thing;

        // 尝试为执行者（pawn）预留目标资源（即僵尸），确保在执行过程中不会被其他作业抢占
        // errorOnFailed：若预留失败是否抛出错误
        // 调用Reserve方法预留目标，控制权为1层，优先级-1（默认），无特定jobDriver，根据errorOnFailed决定是否报错
        public override bool TryMakePreToilReservations(bool errorOnFailed)
        {
            return pawn.Reserve(job.targetA, job, 1, -1, null, errorOnFailed);
        }

        // 构建新的Toil执行序列（即任务步骤列表）
        // 返回一个包含多个Toil的迭代器，按顺序执行各个行为
        protected override IEnumerable<Toil> MakeNewToils()
        {
            // 检查是否启用了Ideology模组，并确认存在名为"Suppress slave"的功能标识
            // 若条件满足，则执行后续抑制逻辑（可能是防止在无相关模组时出错）

            // 若目标A已消失、被销毁或为空，则任务失败
            this.FailOnDespawnedOrNull(TargetIndex.A);
            // 若目标A处于精神状态异常（如发狂、恐慌等），则任务失败
            this.FailOnMentalState(TargetIndex.A);
            // 若目标A未清醒（如睡眠、昏迷），则任务失败
            this.FailOnNotAwake(TargetIndex.A);
            // 若目标A被禁止操作（如被标记为禁用），则任务失败
            this.FailOnForbidden(TargetIndex.A);
            // 自定义失败条件：确保目标A确实是僵尸（通过IsZombie()方法判断）
            this.FailOn(() => !Zombie.IsZombie());
            // 前往奴隶（僵尸）附近位置的Toil
            yield return doGotoZombie(pawn, Zombie);
            // 确保执行者处于可交互状态后再继续
            yield return Toils_Interpersonal.WaitToBeAbleToInteract(pawn);
            // 移动到目标A的可交互位置
            yield return Toils_Interpersonal.GotoInteractablePosition(TargetIndex.A);
            // 将当前游戏tick记录到目标僵尸的mindState中
            yield return SetLastSuppressionTime(TargetIndex.A);
            // 包含实际的交互动作和强制等待逻辑
            yield return TrySuppress(TargetIndex.A);

        }

        // 创建一个名为"TrySuppress"的Toil，用于执行对僵尸的抑制行为
        // 参数zombieInd：指定目标索引（通常是TargetIndex.A）
        private Toil TrySuppress(TargetIndex zombieInd)
        {
            // 创建一个新的Toil实例，名称为"TrySuppress"
            Toil toil = ToilMaker.MakeToil("TrySuppress");
            // 设置该Toil的初始化动作（在开始执行时调用）
            toil.initAction = delegate
            {
                Need_Zombie_Suppress need = null;
                var got = ((Pawn)toil.actor.jobs.curJob.GetTarget(zombieInd).Thing)?.needs?.TryGetNeed(out need);
                if (got == true && need != null)
                {
                    // 执行者（pawn）尝试与僵尸进行“Suppress”类型的交互
                    // InteractionDefOf.Suppress 应为定义好的交互类型（如压制、训诫等）
                    // pawn.interactions.TryInteractWith(Zombie, ZombieDefOf.RI_ZombieSuppress);
                    doTryInteractWith(Zombie, need, ZombieDefOf.RI_Zombie_Int_ZombieSuppress);
                    // 强制僵尸进入等待状态，持续SuppressDuration个tick，由当前执行者控制
                    // 此操作会阻止僵尸进行其他行动
                    PawnUtility.ForceWait(Zombie, SuppressDuration, pawn);
                }
            }
                ;
            // 设置该Toil的社交模式为关闭（不触发随机社交行为）
            toil.socialMode = RandomSocialMode.Off;
            // 设置Toil完成模式为“延迟完成”，即持续运行defaultDuration个tick后才完成
            toil.defaultCompleteMode = ToilCompleteMode.Delay;
            // 设置Toil的默认持续时间为SuppressDuration（180 tick）
            toil.defaultDuration = SuppressDuration;
            // 返回构建好的Toil对象
            return toil;
        }

        // 创建一个名为"SetLastSuppressionTime"的Toil，用于记录最后一次抑制的时间戳
        // 参数targetInd：目标索引，指向被抑制的僵尸
        private Toil SetLastSuppressionTime(TargetIndex targetInd)
        {
            // 创建一个新的Toil实例，名称为"SetLastSuppressionTime"
            Toil toil = ToilMaker.MakeToil("SetLastSuppressionTime");
            // 设置该Toil的初始化动作
            toil.initAction = delegate
            {
                // 获取当前作业中指定目标（targetInd）所对应的Pawn
                // 并将其mindState中的lastSlaveSuppressedTick字段更新为当前游戏tick数
                // 用于追踪上次被抑制的时间，可能影响后续AI行为或冷却判断
                Need_Zombie_Suppress need = null;
                var got = ((Pawn)toil.actor.jobs.curJob.GetTarget(targetInd).Thing)?.needs?.TryGetNeed(out need);
                if (got == true && need != null)
                {
                    need.LastSatisfiedTick = Find.TickManager.TicksGame;
                }
                // 如果需要压制
            };
            // 设置Toil完成模式为“立即完成”，即执行initAction后立刻结束
            toil.defaultCompleteMode = ToilCompleteMode.Instant;
            // 返回构建好的Toil对象
            return toil;
        }

        // 去往僵尸位置
        public static Toil doGotoZombie(Pawn pawn, Pawn talkee)
        {
            Toil toil = ToilMaker.MakeToil("doGotoZombie");
            toil.initAction = delegate
            {
                pawn.pather.StartPath(talkee, PathEndMode.Touch);
            };
            toil.AddFailCondition(delegate
            {
                if (talkee.DestroyedOrNull())
                {
                    return true;
                }

                return !talkee.IsZombie();
            });
            toil.socialMode = RandomSocialMode.Off;
            toil.defaultCompleteMode = ToilCompleteMode.PatherArrival;
            return toil;
        }

        public bool doTryInteractWith(Pawn recipient, Need_Zombie_Suppress need, InteractionDef intDef)
        {
            // 如果开启了调试设置，总是触发社交冲突（用于测试），强制将交互类型设为侮辱
            if (DebugSettings.alwaysSocialFight)
            {
                intDef = InteractionDefOf.Insult;
            }

            // 防止角色与自己进行交互，记录警告并返回失败
            if (pawn == recipient)
            {
                Log.Warning(pawn?.ToString() + " tried to interact with self, interaction=" + intDef.defName);
                return false;
            }


            // 检查当前是否可以与目标进行该类型交互（如距离、状态等），否则返回失败
            if (!CanInteractNowWith(recipient, need, intDef))
            {
                return false;
            }


            // 检查交互冷却时间，防止短时间内重复交互，若太快则报错并返回失败
            if (!intDef.ignoreTimeSinceLastInteraction && InteractedTooRecentlyToInteract(need))
            {
                Log.Error($"{pawn} tried to do interaction {intDef} to {recipient} only {Find.TickManager.TicksGame - need.LastSatisfiedTick} ticks since last interaction (min is {300}).");
                return false;
            }

            // 交互相关的规则包（用于生成日志、文本等）
            List<RulePackDef> list = new List<RulePackDef>();
            // 如果交互定义有发起者思想，则为发起者添加相关思想（如心情变化）
            // if (intDef.initiatorThought != null)
            // {
            //     AddInteractionThought(pawn, recipient, intDef.initiatorThought);
            // }

            // 发起者技能经验获取（如训诫、压制等可提升技能）
            if (intDef.initiatorXpGainSkill != null)
            {
                pawn.skills.Learn(intDef.initiatorXpGainSkill, intDef.initiatorXpGainAmount);
            }

            // 增加意识形态影响（如婴儿暴露度），用于 Ideology 模组
            // recipient.ideo?.IncreaseIdeoExposureIfBaby(pawn.Ideo, 0.5f);

            // 检查是否会触发社交冲突（如镇压失败导致反抗），仅对人类且已生成的角色
            bool flag = false;
            if (recipient.RaceProps.Humanlike && recipient.Spawned)
            {
                flag = recipient.interactions.CheckSocialFightStart(intDef, pawn);
            }

            // 交互后可能触发的信件、日志等内容
            string letterText;
            string letterLabel;
            LetterDef letterDef;
            LookTargets lookTargets;
            // 如果没有触发社交冲突，则调用交互工作者生成日志和信件内容
            if (!flag)
            {
                intDef.Worker.Interacted(pawn, recipient, list, out letterText, out letterLabel, out letterDef, out lookTargets);
            }
            else
            {
                // 若发生社交冲突，则不生成信件内容
                letterText = null;
                letterLabel = null;
                letterDef = null;
                lookTargets = null;
            }

            // 生成交互气泡（视觉效果），如镇压、训诫等
            MoteMaker.MakeInteractionBubble(pawn, recipient, intDef.interactionMote, intDef.GetSymbol(pawn.Faction, pawn.Ideo), intDef.GetSymbolColor(pawn.Faction));
            // 记录本次交互的时间、类型等（用于冷却判断和日志）
            var lastInteraction = intDef.defName;
            var lastInteractionDef = intDef;
            // 同步目标的交互信息（如被镇压后也有冷却）
            need.LastSatisfiedTick = Find.TickManager.TicksGame;
            need.lastInteractionDef = intDef;

            // 若发生社交冲突，添加相关规则包（用于生成特殊日志）
            if (flag)
            {
                list.Add(RulePackDefOf.Sentence_SocialFightStarted);
            }

            // 生成交互日志（用于游戏历史和回放）
            PlayLogEntry_Interaction playLogEntry_Interaction = new PlayLogEntry_Interaction(intDef, pawn, recipient, list);
            Find.PlayLog.Add(playLogEntry_Interaction);
            // 若有信件定义，则发送信件通知玩家
            if (letterDef != null)
            {
                string text = playLogEntry_Interaction.ToGameStringFromPOV(pawn);
                if (!letterText.NullOrEmpty())
                {
                    text = text + "\n\n" + letterText;
                }

                Find.LetterStack.ReceiveLetter(letterLabel, text, letterDef, lookTargets ?? ((LookTargets)pawn));
            }

            // 交互成功，返回 true
            return true;
        }

        public bool CanInteractNowWith(Pawn recipient, Need_Zombie_Suppress need, InteractionDef interactionDef = null)
        {
            if (InteractedTooRecentlyToInteract(need))
            {
                return false;
            }

            if (!pawn.IsCarryingPawn(recipient))
            {
                if (!recipient.Spawned)
                {
                    return false;
                }

                if (!SocialInteractionUtility.IsGoodPositionForInteraction(pawn, recipient))
                {
                    return false;
                }
            }

            if (!SocialInteractionUtility.CanInitiateInteraction(pawn, interactionDef) || !SocialInteractionUtility.CanReceiveInteraction(recipient, interactionDef))
            {
                return false;
            }

            return true;
        }

        public bool InteractedTooRecentlyToInteract(Need_Zombie_Suppress need)
        {
            return Find.TickManager.TicksGame < need.LastSatisfiedTick + 300;
        }
    }

}